package com.thh.project.common.exception;

import com.google.common.collect.ImmutableMap;
import com.thh.project.model.common.dtos.ResponseResult;
import com.thh.project.model.common.enums.AppHttpCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @description:异常处理类
 * @author: thh
 * @time: 2020/6/21 17:34
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //使用EXCEPTIONS存放异常类型和错误代码的映射，ImmutableMap的特点的一旦创建不可改变，并且线程安全
    private static ImmutableMap<Class<? extends Throwable>, AppHttpCodeEnum> EXCEPTIONS;
    //使用builder来构建一个异常类型和错误代码的异常
    protected static ImmutableMap.Builder<Class<? extends Throwable>, AppHttpCodeEnum> builder = ImmutableMap.builder();

    static {
        //在这里加入一些基础的异常类型判断
        builder.put(HttpMessageNotReadableException.class, AppHttpCodeEnum.PARAM_INVALID);
    }
    //状态码500
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    public ResponseResult  handleException(Throwable e, HttpServletRequest request){
        if (EXCEPTIONS == null){
            EXCEPTIONS = builder.build();
        }
        final AppHttpCodeEnum appHttpCodeEnum = EXCEPTIONS.get(e.getClass());
        ResponseResult responseResult = null;
        if (appHttpCodeEnum != null) {
            responseResult = ResponseResult.errorResult(appHttpCodeEnum, e.getMessage());
            log.error("出现了全局异常,地址我是：{},异常:{}",request.getRequestURI(),responseResult);
            return responseResult;
        }
        log.error("出现了全局异常,地址我是：{},异常:{}",request.getRequestURI(),e.getMessage());
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, e.getMessage());

    }
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(BusinessException.class)
    public ResponseResult  handleBusinessException(Throwable e, HttpServletRequest request){
        ResponseResult responseResult = ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, e.getMessage());
        log.error("出现了BusinessException异常,地址我是：{},异常:{}",request.getRequestURI(),responseResult);
        return responseResult;
    }

    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(CommonException.class)
    public ResponseResult  handleCommonException(Throwable e, HttpServletRequest request){
        ResponseResult responseResult = ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, e.getMessage());
        log.error("出现了CommonException异常,地址我是：{},异常:{}",request.getRequestURI(),responseResult);
        return responseResult;
    }

    //校验异常处理
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult  handleBindException(MethodArgumentNotValidException e, HttpServletRequest request){
        BindingResult bindingResult = e.getBindingResult();
        Map<String,Object> map = new HashMap<>();
        if (bindingResult.hasErrors()){
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                map.put(fieldError.getField(),fieldError.getDefaultMessage());
            }
        }
        ResponseResult responseResult = ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, map.toString());
        log.error("出现了CommonException异常,地址我是：{},异常:{}",request.getRequestURI(),map);
        return responseResult;
    }
}
